/*
 * Filename : Tail.java
 * Description : **COMPLETE**
 * History  : Date               Engineer       Description
 *            ------             ------------   --------------------------------
 *            June 13, 2007      waitek         Initial creation. 
 */
package com.lct.eq2.tail;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import com.lct.eq2.data.DataHandler;
import com.lct.eq2.gui.LiteGui;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Tail extends Thread implements Runnable {

    public static final int SYSTEM_LOG = 0;
    public static final int COMBAT_LOG = 1;
    public static final int GUILDNEWS_LOG = 2;
    public static final int CHAT_LOG = 3;
    private boolean running;
    private boolean paused;
    private boolean waitUntilNotified;
    private char[] ch = new char[1];
    private FileInputStream fis = null;
    private BufferedReader br = null;
    public DataHandler dataHandler = null;
    private LiteGui parentGui = null;
    private String fileLocation;
    private Properties props = null;
    private int logType;

    /** Creates a new instance of Tail */
    public Tail(LiteGui parentGui, int logType) {
        props = parentGui.getProgramProperties();
        this.parentGui = parentGui;

        switch (logType) {
            case Tail.SYSTEM_LOG:
                fileLocation = props.getProperty("systemLogPath");
                dataHandler = new DataHandler(this.parentGui, Tail.SYSTEM_LOG, this);
                break;
            case Tail.COMBAT_LOG:
                this.waitUntilNotified = false;
                dataHandler = new DataHandler();
                dataHandler.setParentGui(this.parentGui);
                dataHandler.setTimerParent(this.parentGui.getTimerWindow());
                fileLocation = props.getProperty("combatLogPath");
                this.parentGui.setCombatFileLocation(this.fileLocation);
                this.parentGui.setCombatLogFileName(this.fileLocation.substring(this.fileLocation.lastIndexOf(File.separator) + 1, this.fileLocation.length()));
                break;
            case Tail.GUILDNEWS_LOG:
                fileLocation = props.getProperty("guildLogPath");
                break;
            case Tail.CHAT_LOG:
                fileLocation = props.getProperty("chatLogPath");
                break;
            default:
                break;
        }
        this.logType = logType;

        //dataHandler.setTimerParent(this.parentGui.getTimerWindow());

        //this.moveToEOF();
        this.running = true;
        this.paused = false;
    }

    public int getLogType() {
        return logType;
    }

    public void notifyStart() {
        this.waitUntilNotified = false;
    }

    public void addDataObject(Object o) {
        this.dataHandler.addObjectToEncounter(o);
    }

    public void setParent(LiteGui parent) {
        this.parentGui = parent;
        dataHandler.setParentGui(parent);
    }

    public void setFileLocation(String fileLocation) {
        this.fileLocation = fileLocation;
        //this.moveToEOF();
        this.running = true;
        this.parentGui.setCombatLogFileName(this.fileLocation.substring(this.fileLocation.lastIndexOf(File.separator) + 1, this.fileLocation.length()));
    }

    public void setHandler(DataHandler handler) {
        this.dataHandler = handler;
    }

    public void requestZoneChange(String zone) {
        this.dataHandler.requestZoneChange(zone);
    }

    private void moveToEOF() {
        long before = System.currentTimeMillis();
        //ZoneLocator locator = null;

        try {
            this.fis = new FileInputStream(this.fileLocation);
            if (this.fis.available() > 0) {
                fis.close();

                //System.out.println("File location: " + this.fileLocation);
                File file = new File(this.fileLocation);
                //System.out.println("Attempting to rename file to: " + this.fileLocation.substring(0, this.fileLocation.lastIndexOf("\\") + 1)
                //    + "combat.log_" + this.parentGui.getMainCharacter() + ".txt_" + System.currentTimeMillis());
                File archive = new File(this.fileLocation.substring(0, this.fileLocation.lastIndexOf(File.separator) + 1) + "archive" + File.separator);
                if (!archive.exists()) {
                    archive.mkdir();
                }
                String archivePath = this.fileLocation.substring(0, this.fileLocation.lastIndexOf(File.separator))
                        + File.separator + "archive" + File.separator + (this.logType == Tail.COMBAT_LOG ? "combat.log" : "system.log") + "_" + before;

                //System.out.println("Tail::moveToEOF() - " + archivePath);

                boolean success = file.renameTo(new File(archivePath));
                if (success) {
//                    if (this.logType == Tail.SYSTEM_LOG && !skipZoneLocator) {
//                        this.parentGui.setArchiveFilePath(archivePath);
//                        locator = new ZoneLocator(this.parentGui);
//                    }
                    File newFile = new File(this.fileLocation);
                    try {
                        newFile.createNewFile();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    this.fis = new FileInputStream(fileLocation);
                    this.br = new BufferedReader(new FileReader(fileLocation));
                //System.out.println("File renamed.");
                } else {
                    this.parentGui.setArchiveFilePath(this.fileLocation);
//                    if (this.logType == Tail.SYSTEM_LOG && !skipZoneLocator) {
//                        this.parentGui.setArchiveFilePath(archivePath);
//                        locator = new ZoneLocator(this.parentGui);
//                    }

//                    if (skipZoneLocator) {
                    fis = new FileInputStream(fileLocation);
                    br = new BufferedReader(new FileReader(fileLocation));
                    int available = fis.available();
                    if (available > 0) {
                        br.skip(available);
                        fis.skip(available);
                        if (this.parentGui.fileLocationIsNetwork()) {
                            System.out.println("Network drive, changing method.");
                            String tmp = null;
                            while ((tmp = br.readLine()) != null) {
                            }
                        }
                        System.out.println("It took " + (System.currentTimeMillis() - before) + "ms to skip over " + available + " bytes to the EOF.");
//                        }
                    }
                }
            } else {
                fis = new FileInputStream(fileLocation);
                br = new BufferedReader(new FileReader(fileLocation));
            }
        } catch (FileNotFoundException ex) {
            this.parentGui.stopParse();
            this.stopRunning();
            if (this.logType == Tail.COMBAT_LOG) {
//                ex.printStackTrace();
                this.parentGui.throwError(1);
            } else {
                this.parentGui.throwError(5);
            }
        //ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    public Tail getInstance() {
        return this;
    }

    public void pause() {
        this.paused = true;
    }

    public void unPause() {
        this.paused = false;
    }

    public void startParsing() {
        this.paused = false;
        this.running = true;
    }

    public void stopRunning() {
        this.paused = true;
        this.running = false;
    }

    public void throwError(int error) {
        this.parentGui.stopParse();
        this.stopRunning();
        this.parentGui.throwError(error);
        this.parentGui.setError(error);
    }

    public void run() {
        this.moveToEOF();
        while (this.waitUntilNotified) {
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(Tail.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        String line = null;

        try {
//            FileReader fr = null;
//            BufferedReader buf = null;
            
            File file = new File(this.fileLocation);
            long lastModified = file.lastModified();
            long before = System.currentTimeMillis();
            boolean parsePrevious = Boolean.parseBoolean(this.props.getProperty("parsePrevious"));
            boolean skip = false;
            try {
                if (!parsePrevious) {
                    String archivePath = this.fileLocation.substring(0, this.fileLocation.lastIndexOf(File.separator)) + File.separator
                            + "archive" + File.separator + (this.logType == Tail.COMBAT_LOG ? "combat.log" : "chat.log") + "_" + before;
                    File archive = new File(this.fileLocation.substring(0, this.fileLocation.lastIndexOf(File.separator) + 1) + "archive" + File.separator);
                    if (!archive.exists()) {
                        archive.mkdir();
                    }
                    if (file.length() > 0) {
                        if (file.renameTo(new File(archivePath))) {
                            skip = true;
                            file = new File(this.fileLocation);
                            file.createNewFile();
                        }
                    }
                }
                
//                fr = new FileReader(this.fileLocation);
//                buf = new BufferedReader(fr);
                if (this.parentGui.getError() != -1) {
                    this.parentGui.setError(-1);
                }
                
//                if (!skip) {
//                    if (file.length() > 0) {
//                        if (this.logType == Tail.SYSTEM_LOG) {
//                            buf.skip(file.length() + 1);
//                        }
//                        while ((line = buf.readLine().replaceAll(" ", "")) != null && !line.equalsIgnoreCase("")) {
//                            if (this.logType == Tail.COMBAT_LOG) {
//                                if (parsePrevious) {
//                                    this.dataHandler.addData(line, false, true, null);
//                                }
//                            }
//                        }
//                    }
//                }
            } catch (NullPointerException exc) {
                //nothing
            }
            
            System.out.println("Tail(" + (this.logType == Tail.COMBAT_LOG ? "Combat Log" : "System Log") + ")::run() - Skipping to the EOF took " + (System.currentTimeMillis() - before) + "ms.");
            this.parentGui.startParse();
            while (running) {
                while (!paused && br.ready()) {
                    try {
//                        if (lastModified != file.lastModified()) {
//                            System.out.println(file.lastModified());w
//                            lastModified = file.lastModified();
//                        }
                        
                        while ((line = br.readLine()) != null) {
                            line = line.replaceAll(" ", "");
                            if (!line.equalsIgnoreCase("")) {
                                //System.out.println(line);
                                dataHandler.addData(line, Boolean.parseBoolean(this.props.getProperty("sendData")), false, null);
                                if (this.logType == SYSTEM_LOG){
                                    //System.out.println(line);
                                }
                            }
                        }
                    } catch (NullPointerException exc) {
                        exc.printStackTrace();
                        //nothing
                    }
                    Thread.currentThread().sleep(100);
                }
                Thread.currentThread().sleep(1000);
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Tail.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            this.throwError(1);
        } catch (IOException ex) {
            this.throwError(5);
            Logger.getLogger(Tail.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
